#ifndef BOXES_HPP_GUARD_
#define BOXES_HPP_GUARD_

#include <iostream>

#include "bobox_box.hpp"
#include "bobox_model.hpp"

class almighty_box : public bobox::basic_box2 {
public:

	class model : public bobox::box_model {
	public:
		model(bobox::box_model_id_type id, bobox::box_tid_type tid, bobox::runtime *rt)
			: bobox::box_model(id, tid, rt)
		{}

		virtual box *create(bobox::box_id_type id, bobox::request *req) const
		{
			return new almighty_box(id, tid_, req);
		}
	};

	almighty_box(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req)
		: bobox::basic_box2(id, tid, req)
	{
	}

	virtual void init_impl()
	{
		add_group(group_index_type(0), bobox::column_index_type(0), 1);
		receive(bobox::inarc_index_type(0), group_index_type(0));
	}

	virtual void sync_mach_etwas()
	{
		send_poisoned(bobox::outarc_index_type(0));
	}

};

class source_box : public bobox::basic_box2 {
public:

	class model : public bobox::box_model {
	public:
		model(bobox::box_model_id_type id, bobox::box_tid_type tid, bobox::runtime *rt)
			: bobox::box_model(id, tid, rt)
		{}

		virtual box *create(bobox::box_id_type id, bobox::request *req) const
		{
			return new source_box(id, tid_, req);
		}
	};

	source_box(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req)
		: bobox::basic_box2(id, tid, req), remaining_(10)
	{
	}

	virtual void init_impl()
	{
		add_group(group_index_type(0), bobox::column_index_type(0), 0);
		add_group(
			group_index_type(1),
			bobox::column_index_type(0),
			get_output_descriptors(bobox::outarc_index_type(0)),
			get_output_scalars_descriptor(bobox::outarc_index_type(0))
		);
		receive(bobox::inarc_index_type(0), group_index_type(0));
		allocate(group_index_type(1), 10);
	}

	size_t remaining_;

	virtual void sync_mach_etwas()
	{
		if (remaining_ > 0) {
			for (size_t i=0; i<10; i++) {
				get_data<bobox::int_policy>(bobox::column_index_type(0))[i] = i + 10*remaining_;
			}
			get_group(group_index_type(1)).wrpos_ = 10;

			get_group(group_index_type(1)).scalars_.cell<bobox::string_policy>(bobox::scalar_index_type(0)) = "AHOJ";

			send(bobox::outarc_index_type(0), group_index_type(1));
			allocate(group_index_type(1), 10);
			--remaining_;
		} else {
			send_poisoned(bobox::outarc_index_type(0));
		}
	}

};

class destination_box : public bobox::basic_box2 {
public:

	class model : public bobox::box_model {
	public:
		model(bobox::box_model_id_type id, bobox::box_tid_type tid, bobox::runtime *rt)
			: bobox::box_model(id, tid, rt)
		{}

		virtual box *create(bobox::box_id_type id, bobox::request *req) const
		{
			return new destination_box(id, tid_, req);
		}
	};

	destination_box(bobox::box_id_type id, bobox::box_tid_type tid, bobox::request *req)
		: bobox::basic_box2(id, tid, req)
	{
	}

	virtual void init_impl()
	{
		add_group(group_index_type(0), bobox::column_index_type(0), 2);
		receive(bobox::inarc_index_type(0), group_index_type(0));
	}

	virtual void sync_mach_etwas()
	{
		if (get_group(group_index_type(0)).poisoned_) {
			send_poisoned(bobox::outarc_index_type(0));
		} else {
			for (size_t i=0; i<10; i++) {
				std::cout << get_data<bobox::int_policy>(bobox::column_index_type(0))[i] << std::endl;
			}
			std::cout << get_group(group_index_type(0)).scalars_.cell<bobox::string_policy>(bobox::scalar_index_type(0)) << std::endl;
			receive(bobox::inarc_index_type(0), group_index_type(0));
		}
	}

};


#endif
